package com.sfexpress.tools;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.sfexpress.tools.entity.CmptCheckResult;
import com.sfexpress.tools.entity.MysqlColumnInfo;

/**
 * 
 * mysql列兼容性检查类
 * 
 * @author CrazyPig
 *
 */
public class MysqlColumnCmptChecker {
	
	public void check(List<MysqlColumnInfo> pvColumns, List<MysqlColumnInfo> gvColumns, CmptCheckResult result) throws Exception {
		
		Map<String, MysqlColumnInfo> pvColumnMap = getMap(pvColumns);
		Map<String, MysqlColumnInfo> gvColumnMap = getMap(gvColumns);
		
		// 检查列兼容性
		result = checkCmpt(pvColumnMap, gvColumnMap, result);
		
		if(result.getConflictItems().size() > 0) {
			result.setCompatible(false);
		}
		
	}
	
	/**
	 * 
	 * 检查列兼容性
	 * 
	 * @param pvColumnMap
	 * @param gvColumnMap
	 * @param result
	 * @return
	 * @throws Exception 
	 */
	private CmptCheckResult checkCmpt(Map<String, MysqlColumnInfo> pvColumnMap, Map<String, MysqlColumnInfo> gvColumnMap, CmptCheckResult result) throws Exception {
		
		Set<String> pvColumns = pvColumnMap.keySet();
		Set<String> gvColumns = gvColumnMap.keySet();
		
		Set<String> intersection = new TreeSet<String>();
		intersection.addAll(pvColumns);
		intersection.retainAll(gvColumns);
		
		MysqlColumnCmptChecker colCmptChecker = new MysqlColumnCmptChecker();
		for(String columnName : intersection) {
			// TODO 检查列兼容性
			MysqlColumnInfo pvColumn = pvColumnMap.get(columnName);
			MysqlColumnInfo gvColumn = gvColumnMap.get(columnName);
			colCmptChecker.check(pvColumn, gvColumn, result);
		}
		
		return result;
	}
	
	private Map<String, MysqlColumnInfo> getMap(List<MysqlColumnInfo> columns) {
		Map<String, MysqlColumnInfo> columnMap = new HashMap<String, MysqlColumnInfo>();
		for(MysqlColumnInfo column : columns) {
			columnMap.put(column.getColumnName(), column);
		}
		return columnMap;
	}
	
	public void check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn, CmptCheckResult result) throws Exception {
		
		List<ColumnDefineCmptChecker> checkers = new ArrayList<ColumnDefineCmptChecker>();

		// 列数据类型兼容性检查
		String dataType = gvColumn.getDataType();
		addDataTypeChecker(dataType, checkers);
		
		// ...其他列定义兼容性检查
		
		for(ColumnDefineCmptChecker checker : checkers) {
			boolean isCmpt = checker.check(pvColumn, gvColumn);
			if(!isCmpt) { // 检查出不兼容的情况
				result.getConflictItems().add(new CmptCheckResult.ConflictItem(gvColumn, pvColumn));
			}
		}
			
		
	}
	
	private void addDataTypeChecker(String dataType, List<ColumnDefineCmptChecker> checkers) {
		if("varchar".equalsIgnoreCase(dataType)) {
			checkers.add(new VarcharCmptChecker());
		} else if("char".equalsIgnoreCase(dataType)) {
			checkers.add(new CharCmptChecker());
		} else if("decimal".equalsIgnoreCase(dataType)) {
			checkers.add(new DecimalCmptChecker());
		} else if("double".equalsIgnoreCase(dataType)) {
			checkers.add(new DoubleCmptChecker());
		} else if("float".equalsIgnoreCase(dataType)) {
			checkers.add(new FloatCmptChecker());
		} else {
			checkers.add(new DefaultDataTypeCmptChecker(dataType));
		}
	}
	
	/**
	 * 
	 * 列定义兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public interface ColumnDefineCmptChecker {
		
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) throws Exception;
		
	}
	
	/**
	 * 
	 * 数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static abstract class DataTypeCmptChecker implements ColumnDefineCmptChecker  {
		
		protected String dataType;
		
		public DataTypeCmptChecker(String dataType) {
			this.dataType = dataType;
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			boolean isCmpt = true;
			if(!getDataType().equalsIgnoreCase(pvColumn.getDataType())) {
				isCmpt = false;
			}
			return isCmpt;
		}
		
		public String getDataType() {
			return this.dataType;
		}
		
	}
	
	/**
	 * 
	 * 一般数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class DefaultDataTypeCmptChecker extends DataTypeCmptChecker {

		public DefaultDataTypeCmptChecker(String dataType) {
			super(dataType);
		}
		
	}
	
	/**
	 * 
	 * char数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class CharCmptChecker extends DataTypeCmptChecker {
		
		public static final String DATA_TYPE = "char";
		
		public CharCmptChecker() {
			super(DATA_TYPE);
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			
			if(super.check(pvColumn, gvColumn)) {
				if(pvColumn.getCharMaxLen() == gvColumn.getCharMaxLen()) {
					return true;
				}
			}
			return false;
		
		}
		
	}
	
	/**
	 * 
	 * varchar数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class VarcharCmptChecker extends DataTypeCmptChecker {
		
		public static final String DATA_TYPE = "varchar";
		
		public VarcharCmptChecker() {
			super(DATA_TYPE);
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			
			if(super.check(pvColumn, gvColumn)) {
				if(pvColumn.getCharMaxLen() <= gvColumn.getCharMaxLen()) {
					return true;
				}
			}
			return false;
		
		}
		
	}
	
	/**
	 * 
	 * decimal数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class DecimalCmptChecker extends DataTypeCmptChecker {

		public static final String DATA_TYPE = "decimal";
		
		public DecimalCmptChecker() {
			super(DATA_TYPE);
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			
			if(super.check(pvColumn, gvColumn)) {
				if(pvColumn.getNumericPrecision() <= gvColumn.getNumericPrecision() && 
						pvColumn.getNumericScale() <= gvColumn.getNumericScale()) {
					return true;
				}
			}
			return false;
		
		}
		
	}
	
	/**
	 * 
	 * double数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class DoubleCmptChecker extends DataTypeCmptChecker {
		
		public static final String DATA_TYPE = "double";
		
		public DoubleCmptChecker() {
			super(DATA_TYPE);
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			
			if(super.check(pvColumn, gvColumn)) {
				if(pvColumn.getNumericPrecision() <= gvColumn.getNumericPrecision() && 
						pvColumn.getNumericScale() <= gvColumn.getNumericScale()) {
					return true;
				}
			}
			return false;
		
		}
		
	}
	
	/**
	 * 
	 * float数据类型兼容性检查
	 * 
	 * @author CrazyPig
	 *
	 */
	public static class FloatCmptChecker extends DataTypeCmptChecker {
		
		public static final String DATA_TYPE = "float";
		
		public FloatCmptChecker() {
			super(DATA_TYPE);
		}
		
		@Override
		public boolean check(MysqlColumnInfo pvColumn, MysqlColumnInfo gvColumn) {
			
			if(super.check(pvColumn, gvColumn)) {
				if(pvColumn.getNumericPrecision() <= gvColumn.getNumericPrecision() && 
						pvColumn.getNumericScale() <= gvColumn.getNumericScale()) {
					return true;
				}
			}
			return false;
		
		}
		
	}
	
}
